package com.jdk.demo.unsafe;

import java.lang.reflect.Field;
import java.util.HashMap;
import sun.misc.Unsafe;

public class UnsafeTest2 {
	
	public static void main(String[] args) throws Exception {
		Unsafe unsafe = getUnsafeInstance();
		VO vo = new VO();
		vo.a = 2;
		vo.b = 3;
		vo.d = new HashMap<>();
		// 获取实例字段的偏移地址,偏移最小的那个字段(仅挨着头部)就是对象头的大小
		System.out.println(unsafe.objectFieldOffset(VO.class.getDeclaredField("a")));
		System.out.println(unsafe.objectFieldOffset(VO.class.getDeclaredField("b")));

		// 数组第一个元素的偏移地址,即数组头占用的字节数
		int[] intarr = new int[]{20, 30};
		// Unsafe类中有很多以BASE_OFFSET结尾的常量，比如ARRAY_INT_BASE_OFFSET等，这些常量值是通过arrayBaseOffset方法得到的。arrayBaseOffset方法是一个本地方法，可以获取数组第一个元素的偏移地址。Unsafe类中还有很多以INDEX_SCALE结尾的常量，比如 ARRAY_INT_INDEX_SCALE 等，这些常量值是通过arrayIndexScale方法得到的。将arrayBaseOffset与arrayIndexScale配合使用，可以定位数组中每个元素在内存中的位置
		System.out.println(unsafe.arrayBaseOffset(intarr.getClass()));
		// 数组中每个元素占用的大小
		System.out.println(unsafe.arrayIndexScale(intarr.getClass()));
		System.out.println(unsafe.getInt(intarr, (long)(unsafe.arrayBaseOffset(intarr.getClass()))));
		System.out.println(unsafe.getInt(intarr, (long)(unsafe.arrayBaseOffset(intarr.getClass())) + unsafe.arrayIndexScale(intarr.getClass())));
		
		// 获取类的静态字段偏地址
		System.out.println(unsafe.staticFieldOffset(VO.class.getDeclaredField("f")));
		System.out.println(unsafe.staticFieldOffset(VO.class.getDeclaredField("g")));

		// 获取静态字段的起始地址,通过起始地址和偏移地址,就可以获取静态字段的值了
		// 只不过静态字段的起始地址,类型不是long,而是Object类型
		Object base2 = unsafe.staticFieldBase(VO.class.getDeclaredField("f"));
		System.out.println(base2);
		System.out.println(base2.getClass());//true

		//获取实例字段的属性值
		long aoffset = unsafe.objectFieldOffset(VO.class.getDeclaredField("a"));
		int va = unsafe.getInt(vo, aoffset);
		System.out.println("va="+va);
		

		VO.f = 1024;
		Field sField = VO.class.getDeclaredField("f");
		Object base = unsafe.staticFieldBase(sField);
		long offset = unsafe.staticFieldOffset(sField);
		System.out.println("vf="+unsafe.getInt(base, offset));//1024
		
		System.out.println(unsafe.addressSize());
	}

	private static Unsafe getUnsafeInstance() throws Exception {
		// 通过反射获取rt.jar下的Unsafe类
		Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
		theUnsafeInstance.setAccessible(true);
		// return (Unsafe) theUnsafeInstance.get(null);是等价的
		return (Unsafe) theUnsafeInstance.get(Unsafe.class);
	}

}
